package org.wenhuayuan.uilibrary.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.Scroller;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class HiRefreshLayout extends FrameLayout implements HiRefresh {

    private HiOverView.HiRefreshState mState = HiOverView.HiRefreshState.STATE_INIT;
    private GestureDetector gestureDetector;
    private HiRefresh.HiRefreshListener hiRefreshListener;
    protected HiOverView hiOverView;
    protected AutoScroller autoScroller;

    private int lastY;
    private boolean disableRefreshScroll;


    public HiRefreshLayout(@NonNull Context context) {
        super(context);
        init();
    }

    public HiRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public HiRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    public void setRefreshOverView(HiOverView overView) {
        if(null != hiOverView) {
            removeView(hiOverView);
        }
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        this.hiOverView = overView;
        addView(hiOverView, 0, params);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        // 重新定义header和child的排列
        View header = getChildAt(0);
        View child = getChildAt(1);

        if(null != header && null != child) {
            int childTop = child.getTop();

            if (mState == HiOverView.HiRefreshState.STATE_REFRESH) {
                header.layout(0, hiOverView.mPullRefreshHeight - header.getMeasuredHeight(), right, hiOverView.mPullRefreshHeight);
                child.layout(0, hiOverView.mPullRefreshHeight, right, hiOverView.mPullRefreshHeight + child.getMeasuredHeight());
            } else {
                //left,top,right,bottom
                header.layout(0, childTop - header.getMeasuredHeight(), right, childTop);
                child.layout(0, childTop, right, childTop + child.getMeasuredHeight());
            }

            View other;
            for (int i = 2; i < getChildCount(); i ++) {
                other = getChildAt(i);
                other.layout(0, top, right, bottom);
            }
        }

    }

    @Override
    public void setRefreshDisableScroll(boolean disableScroll) {
        this.disableRefreshScroll = disableScroll;
    }

    @Override
    public void refreshFinished() {
        Log.i("HiRefreshLayout", "===refreshFinished===");
        View header = getChildAt(0);
        hiOverView.onFinish();
        hiOverView.setState(HiOverView.HiRefreshState.STATE_INIT);
        int bottom = header.getBottom();
        if(bottom > 0) {
            recover(bottom);
        }
        mState = HiOverView.HiRefreshState.STATE_INIT;
    }

    @Override
    public void setRefreshListener(HiRefreshListener refreshListener) {
        this.hiRefreshListener = refreshListener;
    }
    final HiGestureDetectorListener listener = new HiGestureDetectorListener(){
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (Math.abs(distanceX) > Math.abs(distanceY) || hiRefreshListener != null && !hiRefreshListener.enableRefresh()) {
                //横向滑动，或刷新被禁止则不处理
                return false;
            }
            if(mState == HiOverView.HiRefreshState.STATE_REFRESH && disableRefreshScroll) {
                return true;// 正在刷新且禁止滚动
            }

            View head = getChildAt(0);
            // 获取可以滚动的子view
            View child = HiScrollUtil.findScrollableChild(HiRefreshLayout.this);
            // 判断当前child是否发生了滚动，滚动则不处理
            boolean isScrolled = HiScrollUtil.childScrolled(child);
            if (isScrolled) {
                return false;
            }

            // 如果没有刷新或没有达到可以刷新的距离，且头部已经滑出或执行下拉
            if((mState != HiOverView.HiRefreshState.STATE_REFRESH || head.getBottom() <= hiOverView.mPullRefreshHeight)
                    && (head.getBottom() >0 || distanceY <=0.0F)) {
                // 还在滑动中
                if(mState != HiOverView.HiRefreshState.STATE_OVER_RELEASE) {
                    int dampY = 0; //计算在阻尼效果下，滑动的距离
                    if (child.getTop() < hiOverView.mPullRefreshHeight){
                        dampY = (int) (lastY/hiOverView.minDamp);
                    } else{
                        dampY = (int) (lastY/hiOverView.maxDamp);
                    }
                    // 如果是正在刷新时，不允许滑动来改变状态
                    boolean bol = moveDown(dampY, true);
                    lastY = (int) (- distanceY);
                    return bol;
                } else {
                    return false;
                }
            } else {
                return false;
            }
//            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    };

    /**
     * 根据偏移量移动 head 和 child
     * @param offsetY 偏移量
     * @param noAuto 是否非自动滚动触发
     * @return
     */
    private boolean moveDown(int offsetY, boolean noAuto) {
        View head = getChildAt(0);
        View child = getChildAt(1);
        int childTop = child.getTop() + offsetY;
        // 异常清况
        if(childTop <= 0) {
            offsetY = - child.getTop();
            // head 和 child移动到原始位置
            head.offsetTopAndBottom(offsetY);
            child.offsetTopAndBottom(offsetY);
            if(HiOverView.HiRefreshState.STATE_REFRESH != mState) {
                mState = HiOverView.HiRefreshState.STATE_INIT;
            }
        } else if(mState == HiOverView.HiRefreshState.STATE_REFRESH && childTop > hiOverView.mPullRefreshHeight) {
            // 如果正在刷新中，禁止继续下拉
            Log.i("HiRefreshLayout", "正在刷新中，禁止继续下拉");
            return false;
        } else if(childTop <= hiOverView.mPullRefreshHeight){
            Log.i("HiRefreshLayout", "还没有超出可刷新的距离");
            // 还没有超出可刷新的距离
            if(noAuto && hiOverView.getState() != HiOverView.HiRefreshState.STATE_VISIBLE) {
                // 如果头开始显示
                hiOverView.onVisible();
                hiOverView.setState(HiOverView.HiRefreshState.STATE_VISIBLE);
                mState = HiOverView.HiRefreshState.STATE_VISIBLE;
            }
            // head 和 child移动到原始位置
            head.offsetTopAndBottom(offsetY);
            child.offsetTopAndBottom(offsetY);
            if(childTop == hiOverView.mPullRefreshHeight
                    && mState == HiOverView.HiRefreshState.STATE_OVER_RELEASE) {
                // 下拉到刷新高度，且松手
                Log.i("HiRefreshLayout", "下拉到刷新高度，且松手");
                refresh();

            }
        } else {
            if(mState != HiOverView.HiRefreshState.STATE_OVER && noAuto){
                Log.i("HiRefreshLayout", "未超出可刷新举例状态，且非自动滚动");
                // 未超出可刷新举例状态，且非自动滚动
                hiOverView.onOverPull();
                hiOverView.setState(HiOverView.HiRefreshState.STATE_OVER);
            }
            // head 和 child移动到原始位置
            head.offsetTopAndBottom(offsetY);
            child.offsetTopAndBottom(offsetY);
        }
        if(null != hiOverView) {
            hiOverView.onScroll(head.getBottom(), hiOverView.mPullRefreshHeight);
        }
        return true;// 返回true表示消费了
    }

    // 执行刷新
    private void refresh() {
        if(hiRefreshListener != null) {
            hiOverView.setState(HiOverView.HiRefreshState.STATE_REFRESH);
            hiOverView.onRefresh();// 这个刷新状态是-用来设置刷新头显示的状态
            mState = HiOverView.HiRefreshState.STATE_REFRESH;
            hiRefreshListener.onRefresh();// 这个刷新状态是-用来接口请求
        }
    }

    private void init() {
        gestureDetector = new GestureDetector(getContext(), listener);
        this.autoScroller = new AutoScroller();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(!autoScroller.isFinished)return false;
        final View header = getChildAt(0); // 获取头部view
        int action = ev.getAction();
//        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_INDEX_MASK) {
//            // 表示用户松开手的状态
//            if(header.getBottom() > 0){
//                // 表示header正在离开顶部，且不处于刷新的状态
//                if (mState != HiOverView.HiRefreshState.STATE_REFRESH) {
//                    recover(header.getBottom());
//                    return false;
//                }
//            }
//            lastY = 0;//滚回去后，重设0
//        }
//        // ======当用户一直下拉不松手======
//        boolean consumer = gestureDetector.onTouchEvent(ev);
//        // 通过consumer来判断是否已经真正的消费
//        // mState不处于初始态、刷新态
//        // 不处于顶部
//        if ((consumer
//                || (mState != HiOverView.HiRefreshState.STATE_INIT
//                && mState != HiOverView.HiRefreshState.STATE_REFRESH)) && header.getBottom() != 0) {
//            // 让父类接受不到真实的这个事件，我们自己进行消费
//            // 其实这样，子类也接受不到真实的事件
//            ev.setAction(MotionEvent.ACTION_CANCEL);
//            return super.dispatchTouchEvent(ev);
//        }
//        if(consumer) {
//            return true;
//        } else {
//            return super.dispatchTouchEvent(ev);
//        }
        switch (action) {
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_POINTER_INDEX_MASK:
                // 表示用户松开手的状态
                if(header.getBottom() > 0){
                    // 表示header正在离开顶部，且不处于刷新的状态
                    if (mState != HiOverView.HiRefreshState.STATE_REFRESH) {
                        recover(header.getBottom());
                        return false;
                    }
                }
                lastY = 0;//滚回去后，重设0
                default:
                    break;
        }
        // ======当用户一直下拉不松手======
        boolean consumer = gestureDetector.onTouchEvent(ev);
        // 通过consumer来判断是否已经真正的消费
        // mState不处于初始态、刷新态
        // 不处于顶部
        if (((mState != HiOverView.HiRefreshState.STATE_INIT
                && mState != HiOverView.HiRefreshState.STATE_REFRESH)) && header.getBottom() != 0) {
            // 让父类接受不到真实的这个事件，我们自己进行消费
            // 其实这样，主要是让子类接受不到真实的事件，这里定义下拉刷新。比如有ScrollView，没有下面
            // 的setAction则，子类会独立滑动
            ev.setAction(MotionEvent.ACTION_CANCEL);
            return super.dispatchTouchEvent(ev);
        }
        if(consumer) {
            return true;
        } else {
            return super.dispatchTouchEvent(ev);
        }
    }

    private void recover(int scrollY) {
        // 这个时候，
        // 如果滚动距离>刷新最小距离，就需要头部滚动到距离顶部=pullRefreshHeight位置
        // 如果滚动距离<刷新最小距离，就需要头部慢慢的滚回去距离顶部=0位置
        if(null != hiRefreshListener && scrollY > hiOverView.mPullRefreshHeight) {
            Log.i("HiRefreshLayout", "scrollY > hiOverView.mPullRefreshHeight");
            int scrollHeight = scrollY - hiOverView.mPullRefreshHeight;
            autoScroller.recover(scrollHeight);
            mState = HiOverView.HiRefreshState.STATE_OVER_RELEASE;
//            hiOverView.setState(HiOverView.HiRefreshState.STATE_OVER_RELEASE);
        } else {
            Log.i("HiRefreshLayout", "scrollY <= hiOverView.mPullRefreshHeight");
            autoScroller.recover(scrollY);
        }
    }
    /**借助Scroller完成视图的自动滚动*/
    private class AutoScroller implements Runnable {
        Scroller scroller;
        int lastY;
        boolean isFinished;
        public AutoScroller() {
            scroller = new Scroller(getContext(), new LinearInterpolator());
            isFinished = true;
        }
        @Override
        public void run() {
            if(scroller.computeScrollOffset()) {
                // 如果还没有完成滚动
                moveDown(lastY - scroller.getCurrY(),false);
                lastY = scroller.getCurrY();
                post(this);
            } else {
                removeCallbacks(this);
                isFinished = true;
            }

        }

        public void recover(int dis) {
            if (dis <= 0) return;
            removeCallbacks(this);

            lastY = 0;
            isFinished = false;scroller.startScroll(0, 0, 0, dis, 300);

            post(this);//执行
        }

        public boolean isFinished () {
            return isFinished;
        }
    }
}
